#ifdef __cplusplus
extern "C"{
#endif
#include "xs_def.h"
#include "xs_fifo.h"
#include "xs_memory.h"
#include "xs_log.h"

#define FIFO_INIT(F)                                  \
  do {                                                \
    struct fifo *Xfifo = (struct fifo *)(F);          \
    Xfifo->next = Xfifo->prev = Xfifo;                \
  } while (0)

#define FIFO_ADD(F,N)                                 \
  do {                                                \
    struct fifo *Xfifo = (struct fifo *)(F);          \
    struct fifo *Xnode = (struct fifo *)(N);          \
    Xnode->next = Xfifo;                              \
    Xnode->prev = Xfifo->prev;                        \
    Xfifo->prev = Xfifo->prev->next = Xnode;          \
  } while (0)

#define FIFO_DEL(N)                                   \
  do {                                                \
    struct fifo *Xnode = (struct fifo *)(N);          \
    Xnode->prev->next = Xnode->next;                  \
    Xnode->next->prev = Xnode->prev;                  \
  } while (0)

#define FIFO_HEAD(F)                                  \
  ((((struct fifo *)(F))->next == (struct fifo *)(F)) \
  ? NULL : (F)->next)

#define FIFO_EMPTY(F)                                 \
  (((struct fifo *)(F))->next == (struct fifo *)(F))

#define FIFO_TOP(F)                                   \
  (FIFO_EMPTY(F) ? NULL : ((struct fifo *)(F))->next)


struct fifo *
xs_fifo_init(void)
{
    struct fifo *xs_fifo_new;

    xs_fifo_new = XCALLOC(MTYPE_FIFO_LIST, 1, sizeof(struct fifo));

    FIFO_INIT(xs_fifo_new);

    return xs_fifo_new;
}

struct fifo *
xs_fifo_add(struct fifo *F, struct fifo *N)
{
    if(F == NULL || N == NULL)
    {
        xs_logd("can not add to fifo");
        return NULL;
    }

    FIFO_ADD(F, N);

    return F;
}

struct fifo *
xs_fifo_del(struct fifo *N)
{
    struct fifo *next;

    assert(N);

    next = N->next;

    FIFO_DEL(N);

    XFREE(MTYPE_FIFO_LIST, N);

    return next;
}


void fifo_test()
{
    struct fifo *root;
    struct fifo *N,*P,*Q;

    root = xs_fifo_init();
#if 0
    /* Next and prev point to the same address when call xs_fifo_init function */
    xs_logd("root: %p, root->next: %p, root->prev: %p", root, root->next, root->prev);

    xs_logd("-------------------------------------------------------------------------");
#endif
    N = xs_fifo_init();
    xs_fifo_add(root, N);
#if 0
    xs_logd("root: %p, root->next: %p, root->prev: %p", root, root->next, root->prev);
    xs_logd("N: %p, N->next: %p, N->prev: %p",
            N, N->next, N->prev);

    xs_logd("-------------------------------------------------------------------------");
#endif
    P = xs_fifo_init();
    xs_fifo_add(root, P);
#if 0
    xs_logd("root: %p, root->next: %p, root->prev: %p",
            root, root->next, root->prev);
    xs_logd("N: %p, N->next: %p, N->prev: %p",
            N, N->next, N->prev);
    xs_logd("P: %p, P->next: %p, P->prev: %p",
            P, P->next, P->prev);
#endif
    xs_fifo_del(N);
    xs_fifo_del(P);
#if 0
    xs_logd("-------------------------------------------------------------------------");

    xs_logd("root: %p, root->next: %p, root->prev: %p",
            root, root->next, root->prev);
    xs_logd("N: %p, N->next: %p, N->prev: %p",
            N, N->next, N->prev);
    xs_logd("P: %p, P->next: %p, P->prev: %p",
            P, P->next, P->prev);
#endif

    xs_fifo_del(root);
}

#ifdef __cplusplus
}
#endif